package de.dailab.graphworld.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import de.dailab.graphworld.ontology.Graph;
import de.dailab.graphworld.ontology.Node;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.group6.view.PanelInfo;

public class GraphWorldMenuBar extends JMenuBar {

    private static final long serialVersionUID = -4353821389161173562L;
    private GraphWorldGUI gui;
    final JMenu mFile = new JMenu("File");
    final JMenu mEditor = new JMenu("Editor");
    final JMenu mSupp = new JMenu("Support");
    final JMenuItem miRandom = new JMenuItem("Create Random Graph");
    final JMenuItem miLoad = new JMenuItem("Load Graph");
    final JMenuItem miSave = new JMenuItem("Save Graph");
    final JMenuItem miExit = new JMenuItem("Exit Editor");
    final JMenuItem miAbout = new JMenuItem("About");
    final JMenuItem miHelp = new JMenuItem("Help");
    final JMenuItem miCreate = new JMenuItem("Create New Graph");
    final JMenuItem miAddNode = new JMenuItem("Add Node");
    final JMenuItem miAddEdge = new JMenuItem("Edit Edge");
    final JMenuItem miRemNode = new JMenuItem("Remove Last Node");
    final JMenuItem miSetGold = new JMenuItem("Set Gold");

    public GraphWorldMenuBar(GraphWorldGUI gui, boolean editormode) {

        this.gui = gui;
        createMenuBar();

        mFile.add(miLoad);
        mFile.add(miSave);
        mFile.addSeparator();
        mFile.add(miExit);
        mEditor.add(miCreate);
        mEditor.add(miRandom);
        mEditor.addSeparator();
        mEditor.add(miAddNode);
        mEditor.add(miRemNode);
        mEditor.add(miAddEdge);
        mEditor.add(miSetGold);
        mSupp.add(miAbout);
        if (editormode) {
            mSupp.add(miHelp);
        }

        miRemNode.setEnabled(false);
        miSetGold.setEnabled(false);
        miAddEdge.setEnabled(false);
        miAddNode.setEnabled(false);

        if (editormode) {
            this.add(mFile);
            this.add(mEditor);
        }
        this.add(mSupp);
    }

    private void createMenuBar() {

        // create menus
        mFile.setMnemonic('F');
        mEditor.setMnemonic('E');
        mSupp.setMnemonic('S');

        // create menuitems
        miRandom.setMnemonic('R');
        miLoad.setMnemonic('L');
        miSave.setMnemonic('S');
        miExit.setMnemonic('X');
        miAbout.setMnemonic('A');
        miHelp.setMnemonic('H');
        miCreate.setMnemonic('C');
        miAddNode.setMnemonic('N');
        miAddEdge.setMnemonic('E');
        miRemNode.setMnemonic('L');
        miSetGold.setMnemonic('G');

        // add actionlisteners
        // create random graph
        miRandom.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("" + JOptionPane.OK_OPTION + "  " + JOptionPane.YES_OPTION);
                int retVar = JOptionPane.showConfirmDialog(gui, "Create random graph?\nThe old graph will be discarded.", "Confirm", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                if (retVar == JOptionPane.OK_OPTION) {
                    gui.setGraph(new Graph(new Random(), 25));
                    updateMenu();
                }
            }
        });
        // load graph
        miLoad.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                int approve;
                if (gui.graph != null) {
                    approve = JOptionPane.showConfirmDialog(gui, "Load graph?\nThe old graph will be discarded.", "Confirm", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                } else {
                    approve = JOptionPane.YES_OPTION;
                }
                if (approve == JOptionPane.YES_OPTION) {
                    JFileChooser fc = new JFileChooser();
                    int retVar = fc.showOpenDialog(gui);
                    if (retVar == JFileChooser.APPROVE_OPTION) {
                        gui.load(fc.getSelectedFile());
                        updateMenu();
                    }
                } else {
                    JOptionPane.showMessageDialog(gui, "Loading aborted", "User input", JOptionPane.INFORMATION_MESSAGE);
                }
            }
        });
        // save graph
        miSave.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                gui.save();
            }
        });
        // exit program
        miExit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                @SuppressWarnings("unused")
                GraphWorldLauncher gwl = new GraphWorldLauncher();
                gui.dispose();
            }
        });
        // create empty graph to edit
        miCreate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    int retVar = JOptionPane.showConfirmDialog(gui, "Create new graph?\nThe old graph will be discarded.", "Confirm", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                    if (retVar == JOptionPane.OK_OPTION) {
                        gui.setGraph(new Graph());
                        updateMenu();
                    }
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(gui, "Wrong input.", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        // add node in a graph
        miAddNode.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    JTextField xCoord = new JTextField();
                    JTextField yCoord = new JTextField();
                    Object[] message = {"x-coordinate", xCoord, "y-coordinate", yCoord};
                    int retVar = JOptionPane.showOptionDialog(gui, message, "Add Edge", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null);
                    if (retVar == JOptionPane.OK_OPTION) {
                        int x = Integer.parseInt(xCoord.getText());
                        int y = Integer.parseInt(yCoord.getText());
                        if (x >= 0 && y >= 0) {
                            gui.graph.addNode(x, y, 0);
                            gui.update();
                            updateMenu();
                        } else {
                            JOptionPane.showMessageDialog(gui, "Only positive values allowed.", "Error", JOptionPane.ERROR_MESSAGE);
                        }
                    }
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(gui, "Wrong input.", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        // add edge in a graph
        miAddEdge.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    JTextField firstID = new JTextField();
                    JTextField secondID = new JTextField();
                    JTextField distance = new JTextField();
                    Object[] message = {"From node", firstID, "To node", secondID, "Weight", distance};
                    int retVar = JOptionPane.showOptionDialog(gui, message, "Edit Edge", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null);
                    if (retVar == JOptionPane.OK_OPTION) {
                        gui.graph.editEdge(Integer.parseInt(firstID.getText()), Integer.parseInt(secondID.getText()), Short.parseShort(distance.getText()));
                        gui.update();
                        updateMenu();
                    }
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(gui, "Wrong input.", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        // remove last created node
        miRemNode.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    int retVal = JOptionPane.showConfirmDialog(gui, "Remove node with ID=" + gui.graph.getNodes().get(gui.graph.getNodes().size() - 1).getID() + " ?\nEdges will be removed automatically.", "Remove Node", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                    if (retVal == JOptionPane.YES_OPTION) {
                        gui.graph.removeLastNode();
                        updateMenu();
                        gui.update();
                    }
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(gui, "Wrong input.", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        // set gold value on a node
        miSetGold.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                JTextField nodeID = new JTextField();
                JTextField gold = new JTextField();
                Object[] message = {"Node ID", nodeID, "Units of Gold", gold};
                int retVar = JOptionPane.showOptionDialog(gui, message, "Set Gold Amount", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null);
                if (retVar == JOptionPane.OK_OPTION) {
                    gui.graph.getNodes().get(Integer.parseInt(nodeID.getText())).setGold(Integer.parseInt(gold.getText()));
                    gui.update();
                }
            }
        });
        // get release infos
        miAbout.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        JFrame frameAbout = new JFrame();
                        PanelInfo info = new PanelInfo();
                        frameAbout.add(info);
                        frameAbout.pack();
                        frameAbout.setVisible(true);
                    }
                });
            }
        });
        // get help data
        miHelp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("Nobody will help - abandon all hope!");
            }
        });
    }

    private void updateMenu() {

        // check if graph exists
        boolean b = (gui.graph != null);

        // check if any edges exist
        boolean e = false;
        if (b) {
            for (Node n : gui.graph.getNodes()) {
                if (!n.getEdges().isEmpty()) {
                    e = true;
                    break;
                }
            }
        }

        // remove nodes and change gold only when nodes exist
        miRemNode.setEnabled(b && gui.graph.getNodes().size() > 0);
        miSetGold.setEnabled(b && gui.graph.getNodes().size() > 0);

        // add edges only when at least two nodes exist
        miAddEdge.setEnabled(b && gui.graph.getNodes().size() > 1);

        // start/save only when a graph with edges exists
        miSave.setEnabled(e);

        // add node only when graph exists
        miAddNode.setEnabled(b);
    }
}
